package com.iwhalecloud.citybrain.flow.platform.manager.application.utils;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

import com.aliyun.gts.bpaas.framework.api.rest.dto.ResultResponse;
import com.aliyun.gts.delivery.enterprise.sdk.orgaccount.out.AccountInfo;
import com.fasterxml.jackson.databind.JsonNode;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.context.MessageSenderContext;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.ProcessInstanceStatusEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.common.enums.TaskLinkStatusEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.MessageSenderManager;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl.OrgAccountServiceAdapter;
import com.iwhalecloud.citybrain.flow.platform.manager.application.service.impl.task.SyncProcessTaskProcessor;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.enums.MsgTypeEnum;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowParticipantInfoVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.FlowProcessInstanceTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.ProcessModelVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.monitor.FlowTaskTraceVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.notice.FlowNoticeTemplateVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.model.task.TaskDueDateVo;
import com.iwhalecloud.citybrain.flow.platform.manager.domain.repository.*;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.RepositoryService;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.engine.impl.bpmn.behavior.MultiInstanceActivityBehavior;
import org.flowable.engine.impl.persistence.entity.ExecutionEntity;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.identitylink.service.impl.persistence.entity.IdentityLinkEntity;
import org.flowable.task.api.Task;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

/**
 * @author cheng.huaxing
 * @date 2019-02-26
 */
@Component
public class FlowUtils {

    private RepositoryService repositoryService;

    private RuntimeService runtimeService;

    private TaskService taskService;

    private ProcessInstanceRepository processInstanceRepository;

    @Autowired
    private void setFlowService(RepositoryService repositoryService, RuntimeService runtimeService,
                                TaskService taskService, ProcessInstanceRepository processInstanceRepository) {
        FLOW_UTILS.repositoryService = repositoryService;
        FLOW_UTILS.runtimeService = runtimeService;
        FLOW_UTILS.taskService = taskService;
        FLOW_UTILS.processInstanceRepository = processInstanceRepository;
    }

    private FlowUtils() {
    }

    private final static FlowUtils FLOW_UTILS;

    static {
        FLOW_UTILS = new FlowUtils();
    }

    public static FlowUtils getInstance() {
        return FLOW_UTILS;
    }


    /**
     * 从流程变量为任务设置参与人，针对sdk接口启动流程前设置办理人场景
     *
     * @param taskEntity
     */
    public void setProcessInstanceParticipantsFromVariable(TaskEntity taskEntity) {
        // 判断是否会签任务
        if (isMultiTaskActivity(taskEntity.getProcessInstanceId(), taskEntity.getTaskDefinitionKey())) {
            return;
        }
        Map<String, Object> variableMap = runtimeService.getVariables(taskEntity.getProcessInstanceId());
        if (Objects.isNull(variableMap)) {
            return;
        }
        // 设置当前任务参与人（非会签任务）
        Set<Map.Entry<String, Object>> entrySet = variableMap.entrySet();
        for (Map.Entry<String, Object> entry : entrySet) {
            if (taskEntity.getTaskDefinitionKey().equals(entry.getKey())) {
                String[] users = entry.getValue().toString().split(",");
                if (users.length == 1) {
                    taskService.setAssignee(taskEntity.getId(), users[0]);
                } else {
                    for (String user : users) {
                        taskService.addCandidateUser(taskEntity.getId(), user);
                    }
                }
            }
        }

    }

    /**
     * 流程节点跳转
     *
     * @param processInstance
     * @param currentActivityId
     * @param newActivityId
     */
    public void changeActivityState(ProcessInstance processInstance, String taskId, String currentActivityId, String newActivityId, Set<String> executionIdList, Set<String> mulExecutionIdList) {
        String processInstanceId = processInstance.getProcessInstanceId();
        List<Execution> executionList = runtimeService.createExecutionQuery().parentId(processInstanceId).list();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        FlowElement currentFlowElement = bpmnModel.getFlowElement(currentActivityId);
        FlowElement targetFlowElement = bpmnModel.getFlowElement(newActivityId);
        newActivityId = this.findTargetActivityId(targetFlowElement, newActivityId);
        if (CollectionUtils.isEmpty(executionList) || executionList.size() == 0) {
            return;
        }
        if (executionList.size() == 1 && ((Activity)currentFlowElement).getLoopCharacteristics() == null) {
            runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId)
                    .moveActivityIdTo(currentActivityId, newActivityId).changeState();
        } else {
            if(((Activity) currentFlowElement).getBehavior() instanceof MultiInstanceActivityBehavior){
                String executionId;
                if(StringUtils.isNotEmpty(taskId)){
                    Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
                    executionId = task.getExecutionId();
                }else {
                    executionId = executionList.stream()
                            .filter(execution -> execution.getActivityId().equals(currentActivityId))
                            .findAny()
                            .map(Execution::getId)
                            .orElse("");
                }
                if(StringUtils.isNotEmpty(executionId)){
                    this.deleteMulExecution(runtimeService.createExecutionQuery().executionId(executionId).singleResult());
                }
                mulExecutionIdList.add(executionId);
                executionIdList.addAll(runtimeService.createExecutionQuery().parentId(executionId).list().stream().map(Execution::getId).collect(Collectors.toList()));
            }
            List<List<FlowElement>> flowTraces = new ArrayList<>();
            this.queryAllTrace(new ArrayList<>(bpmnModel.getMainProcess().getFlowElements()), flowTraces);
            String targetActivityId = newActivityId;
            List<String> executionIds = executionList.stream()
                    .filter(execution -> {
                        if(execution.getActivityId().equals(currentActivityId) || execution.getActivityId().equals(targetActivityId)){
                            return true;
                        }else{
                            FlowElement element = bpmnModel.getFlowElement(execution.getActivityId());
                            if (((Activity) element).getBehavior() instanceof MultiInstanceActivityBehavior) {
                                mulExecutionIdList.add(execution.getId());
                                executionIdList.addAll(runtimeService.createExecutionQuery().parentId(execution.getId()).list().stream().map(Execution::getId).collect(Collectors.toList()));
                                runtimeService.deleteMultiInstanceExecution(execution.getId(), true);
                                return false;
                            }
                            List<List<FlowElement>> list = flowTraces.stream().filter(flowElements -> {
                                List<FlowElement> filterElements = flowElements.stream()
                                        .filter(flowElement -> {
                                            if(flowElement.getId().equals(targetActivityId) || flowElement.getId().equals(execution.getActivityId())){
                                                return true;
                                            }
                                            if(flowElement instanceof SubProcess){
                                                return ((SubProcess)flowElement).getFlowElement(targetActivityId) != null || ((SubProcess)flowElement).getFlowElement(execution.getActivityId()) != null;
                                            }
                                            return false;
                                        })
                                        .collect(Collectors.toList());
                                return filterElements.size() == 2;
                            }).collect(Collectors.toList());
                            return list.size() > 0;
                        }
                    })
                    .map(Execution::getId)
                    .collect(Collectors.toList());
            executionIdList.addAll(executionIds);
            if(executionIds.size() == 1){
                runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId)
                        .moveExecutionToActivityId(executionIds.get(0), targetActivityId).changeState();
            }else{
                runtimeService.createChangeActivityStateBuilder().processInstanceId(processInstanceId)
                        .moveExecutionsToSingleActivityId(executionIds, targetActivityId).changeState();
            }
        }

    }

    private void deleteMulExecution(Execution execution) {
        List<Execution> executions = runtimeService.createExecutionQuery().parentId(execution.getParentId()).list();
        if (!CollectionUtils.isEmpty(executions)) {
            executions.forEach(e -> runtimeService.deleteMultiInstanceExecution(e.getId(), true));
        }
    }

    public void queryAllTrace(List<FlowElement> elements, List<List<FlowElement>> flowTraces) {
        elements.stream()
                .filter(flowElement -> flowElement instanceof StartEvent)
                .findFirst().ifPresent(startElement -> this.recusionFlowElement(flowTraces, new ArrayList<>(), startElement));

    }

    public void recusionFlowElement(List<List<FlowElement>> flowTraces, List<FlowElement> flowElements, FlowElement startElement) {
        List<SequenceFlow> outgoingFlows = new ArrayList<>();
        if(startElement instanceof StartEvent){
            outgoingFlows = ((StartEvent) startElement).getOutgoingFlows();
            flowElements.add(startElement);
        }else if(startElement instanceof Activity){
            //TODO 子流程需判断处理
            outgoingFlows = ((Activity) startElement).getOutgoingFlows();

        }else if(startElement instanceof Gateway){
            outgoingFlows = ((Gateway) startElement).getOutgoingFlows();
        }
        outgoingFlows.forEach(outgoingFlow->{
            List<FlowElement> flowElementList = new ArrayList<>(flowElements);
            FlowElement targetFlowElement = outgoingFlow.getTargetFlowElement();
            flowElementList.add(targetFlowElement);
            if(targetFlowElement instanceof EndEvent){
                flowTraces.add(flowElementList);
            }else{
                this.recusionFlowElement(flowTraces, flowElementList, targetFlowElement);
            }
        });
    }

    /**
     * 属于并发网关, 包含网关 返回网关的ActivityId，否则返回本身ActivityId
     *
     * @param targeFlowElement
     * @param newActivityId
     * @return 跳转的ActivityId
     */
    public String findTargetActivityId(FlowElement targeFlowElement, String newActivityId) {
        if (targeFlowElement instanceof Event) {
            return targeFlowElement.getId();
        }
        if (targeFlowElement instanceof Activity) {
            //TODO 网关  子流程特殊处理
            Activity activity = (Activity) targeFlowElement;
            List<SequenceFlow> sequenceFlows = activity.getIncomingFlows();
            for (SequenceFlow sequenceFlow : sequenceFlows) {
                FlowElement flowElement = sequenceFlow.getSourceFlowElement();
                if (flowElement instanceof ParallelGateway) {
                    return flowElement.getId();
                }
                if (flowElement instanceof InclusiveGateway) {
                    return flowElement.getId();
                }
            }
        }
        return newActivityId;
    }

    /**
     * 是否会签任务
     *
     * @param activityId
     * @return
     */
    public Boolean isMultiTaskActivity(String processInstanceId, String activityId) {
        FlowProcessInstanceTraceRepository processInstanceTraceService = SpringUtils.getBean(FlowProcessInstanceTraceRepository.class);
        FlowProcessInstanceTraceVo pit = processInstanceTraceService.getProcessInstanceTraceByProcessInstanceId(processInstanceId);
        FlowElement flowElement = repositoryService.getBpmnModel(pit.getProcessDefinitionId()).getFlowElement(activityId);
        if (flowElement instanceof UserTask) {
            MultiInstanceLoopCharacteristics multiInstanceLoopCharacteristics = ((UserTask) flowElement).getLoopCharacteristics();
            return Objects.nonNull(multiInstanceLoopCharacteristics);
        }
        return false;
    }

    /**
     * 设置任务超时时间
     *
     * @param taskId 任务id
     * @param date   超时时间
     */
    private void setTaskDueDate(String taskId, Date date) {
        taskService.setDueDate(taskId, date);
    }

    /**
     * 设置流程当前任务超时时间
     *
     * @param processInstance
     */
    public void setCurrentTaskDueDate(ProcessInstance processInstance) {
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(processInstance.getDeploymentId()).singleResult();
        if (Objects.isNull(processDefinition)) {
            return;
        }

        // 保存当前没有超时时间的任务
        Map<String, Task> taskMap = new HashMap<>(8);
        // 获取当前任务
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).list();
        if (CollectionUtils.isEmpty(taskList)) {
            return;
        }
        for (Task task : taskList) {
            if (Objects.isNull(task.getDueDate())) {
                taskMap.put(task.getTaskDefinitionKey(), task);
            }
        }
        handleTaskDueDate(processInstance, processDefinition, taskMap);
    }

    private static String getChildShapeType(JsonNode jsonNode) {
        JsonNode jn = jsonNode.get("stencil");
        if (jn == null) {
            return null;
        }
        jn = jn.get("id");
        if (jn == null) {
            return null;
        }

        return jn.asText();
    }

    private void handleTaskDueDate(ProcessInstance processInstance, ProcessDefinition processDefinition, Map<String, Task> taskMap) {
        // 获取部署模型json数据
        InputStream inputStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), processDefinition.getResourceName() + ".json");
        ProcessModelVo processModel = ModelUtils.getInstance().streamToModel(inputStream);
        List<Object> childShapes = processModel.getChildShapes();
        for (Object childShape : childShapes) {
            JsonNode jsonNode = JsonUtils.readTree(JsonUtils.toJson(childShape));
            if (jsonNode != null) {
                String type = getChildShapeType(jsonNode);
                if ("UserTask".equals(type)) {
                    // 是否设置超时时间
                    JsonNode dueDateNode = jsonNode.get("properties").get("duedate");
                    if (Objects.isNull(dueDateNode)) {
                        continue;
                    }
                    TaskDueDateVo taskDueDateVo = JsonUtils.toObject(JsonUtils.toJson(dueDateNode), TaskDueDateVo.class);

                    String id = jsonNode.get("properties").get("overrideid").asText();
                    if (taskMap.containsKey(id)) {
                        Task task = taskMap.get(id);
                        // 计算超时时间
                        Date dueDate;
                        if (Objects.nonNull(taskDueDateVo) && "start".equals(taskDueDateVo.getRelativeTime())) {
                            dueDate = DateUtils.getRelativeTime(processInstance.getStartTime(), taskDueDateVo.getDay(), taskDueDateVo.getHour(), taskDueDateVo.getMinute(), taskDueDateVo.getSecond());
                        } else if (Objects.nonNull(taskDueDateVo) && "arrive".equals(taskDueDateVo.getRelativeTime())) {
                            dueDate = DateUtils.getRelativeTime(task.getCreateTime(), taskDueDateVo.getDay(), taskDueDateVo.getHour(), taskDueDateVo.getMinute(), taskDueDateVo.getSecond());
                        } else {
                            continue;
                        }
                        setTaskDueDate(task.getId(), dueDate);
                    }
                }
            }
        }
    }

    /**
     * 获取流程当前任务ActivityId列表
     *
     * @param processInstanceId
     * @return
     */
    public List<String> findCurrentActivityId(String processInstanceId) {
        List<String> currentActivityIdList = new ArrayList<>();
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        if (CollectionUtils.isEmpty(taskList)) {
            return currentActivityIdList;
        }

        for (Task task : taskList) {
            currentActivityIdList.add(task.getTaskDefinitionKey());
        }
        return currentActivityIdList;
    }

    /**
     * 获取流程当前任务ExecutionId列表
     *
     * @param processInstanceId
     * @return
     */
    public List<String> findCurrFlowAllExecutionId(String processInstanceId) {
        List<String> currentExecutionIdList = new ArrayList<>();
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstanceId).list();
        if (CollectionUtils.isEmpty(taskList)) {
            return currentExecutionIdList;
        }

        for (Task task : taskList) {
            currentExecutionIdList.add(task.getExecutionId());
        }
        return currentExecutionIdList;
    }


    /**
     * 获取上一个任务节点
     *
     * @param currentActivityId 当前节点
     * @param processInstance   流程实例
     * @return 上一个任务节点
     */
    public List<FlowElement> getFirstFrontElement(String currentActivityId, ProcessInstance processInstance) {
        return getFirstFrontElement(currentActivityId, processInstance.getProcessDefinitionId());
    }

    public List<FlowElement> getFirstFrontElement(String currentActivityId, String processDefinitionId) {
        List<FlowElement> result = new ArrayList<>();
        FlowElement currentFlowElement = repositoryService.getBpmnModel(processDefinitionId).getFlowElement(currentActivityId);
        if (Objects.isNull(currentFlowElement) || currentFlowElement instanceof Event) {
            return result;
        }
        Set<String> processedElementIds = new HashSet<>();
        if (currentFlowElement instanceof FlowNode) {
            processedElementIds.add(currentFlowElement.getId());
            List<SequenceFlow> incomingFlows = ((FlowNode) currentFlowElement).getIncomingFlows();
            boolean found = false;
            //第一次循环，查找直连的任务节点
            for (SequenceFlow sf : incomingFlows) {
                if (sf.getSourceFlowElement() instanceof UserTask) {
                    processedElementIds.add(sf.getSourceFlowElement().getId());
                    found = true;
                    result.add(sf.getSourceFlowElement());
                }
            }
            //若没有找到，则进行第二次循环，递归查找
            if (!found) {
                for (SequenceFlow sf : incomingFlows) {
                    result.addAll(getFirstFrontElement(sf.getSourceFlowElement(), processedElementIds));
                }
            }
        }
        return result;
    }

    private List<FlowElement> getFirstFrontElement(FlowElement currentElement, Set<String> processedElementIds) {
        List<FlowElement> result = new ArrayList<>();
        if (processedElementIds.contains(currentElement.getId())) {
            return result;
        }
        processedElementIds.add(currentElement.getId());
        if (currentElement instanceof Event) {
            return result;
        }
        if (currentElement instanceof FlowNode) {
            List<SequenceFlow> incomingFlows = ((FlowNode) currentElement).getIncomingFlows();
            boolean found = false;
            //第一次循环，查找直连的任务节点
            for (SequenceFlow sf : incomingFlows) {
                if (sf.getSourceFlowElement() instanceof UserTask) {
                    processedElementIds.add(sf.getSourceFlowElement().getId());
                    found = true;
                    result.add(sf.getSourceFlowElement());
                }
            }
            //若没有找到，则进行第二次循环，递归查找
            if (!found) {
                for (SequenceFlow sf : incomingFlows) {
                    result.addAll(getFirstFrontElement(sf.getSourceFlowElement(), processedElementIds));
                }
            }
        }
        return result;
    }

    public void setTaskDueDate(TaskEntity taskEntity) {
        if (Objects.isNull(taskEntity) || Objects.nonNull(taskEntity.getDueDate())) {
            return;
        }
        Map<String, Task> taskMap = new HashMap<>(2);
        taskMap.put(taskEntity.getTaskDefinitionKey(), taskEntity);
        ExecutionEntity processInstance = processInstanceRepository.findById(taskEntity.getProcessInstanceId());
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(processInstance.getProcessDefinitionId())
                .singleResult();

//        handleTaskDueDate(processInstance, processDefinition, taskMap);
    }

    public ProcessInstance getProcessInstance(String processInstanceId) {
        return runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
    }

    public List<FlowElement> getFlowElementBeforeCurrentElement(Process process, String currentActivityId) {
        FlowElement currentElement = process.getFlowElement(currentActivityId);
        Set<String> processedElementIds = new HashSet<>();
        return getFlowElementBeforeCurrentElement(process, currentElement, false, processedElementIds);
    }

    private List<FlowElement> getFlowElementBeforeCurrentElement(Process process, FlowElement currentElement, boolean include, Set<String> processedElementIds) {
        List<FlowElement> result = new ArrayList<>();
        if (currentElement == null || processedElementIds.contains(currentElement.getId())) {
            return result;
        }
        processedElementIds.add(currentElement.getId());
        if (currentElement instanceof SequenceFlow) {
            //如果是连线，则获取来源节点
            result.addAll(getFlowElementBeforeCurrentElement(process, ((SequenceFlow) currentElement).getSourceFlowElement(), true, processedElementIds));
        }

        if (currentElement instanceof Event) {
            return result;
        }

        if (currentElement instanceof FlowNode) {
            //1.如果是任务节点
            if (currentElement instanceof UserTask) {
                //todo 排除掉并发节点
                //1.1 加入返回结果
                if (include && !isParallelTask((FlowNode) currentElement)) {
                    result.add(currentElement);
                }
                //1.2 获取来源节点
                List<SequenceFlow> incomingFlows = ((UserTask) currentElement).getIncomingFlows();
                for (SequenceFlow sf : incomingFlows) {
                    result.addAll(getFlowElementBeforeCurrentElement(process, sf, true, processedElementIds));
                }
                return result;
            }

            //2.
            List<SequenceFlow> incomingFlows = ((FlowNode) currentElement).getIncomingFlows();
            for (SequenceFlow sf : incomingFlows) {
                result.addAll(getFlowElementBeforeCurrentElement(process, sf, true, processedElementIds));
            }

        }
        return result;
    }

    private boolean isParallelTask(FlowNode currentElement) {
        //1.往前找到并行网关
        //2.往后找到并行网关
        return findParallelGatewayBeforeElement(currentElement) && findParallelGatewayAfterElement(currentElement);
    }

    private boolean findParallelGatewayAfterElement(FlowElement currentElement) {
        if (currentElement instanceof ParallelGateway) {
            return true;
        }
        if (currentElement instanceof SequenceFlow) {
            return findParallelGatewayAfterElement(((SequenceFlow) currentElement).getTargetFlowElement());
        }
        if (currentElement instanceof Activity) {
            for (SequenceFlow sf : ((Activity) currentElement).getOutgoingFlows()) {
                if (findParallelGatewayAfterElement(sf)) {
                    return true;
                }
            }
        }
        return false;
    }

    private boolean findParallelGatewayBeforeElement(FlowElement currentElement) {
        if (currentElement instanceof ParallelGateway) {
            return true;
        }
        if (currentElement instanceof SequenceFlow) {
            return findParallelGatewayBeforeElement(((SequenceFlow) currentElement).getSourceFlowElement());
        }
        if (currentElement instanceof Activity) {
            for (SequenceFlow sf : ((Activity) currentElement).getIncomingFlows()) {
                if (findParallelGatewayBeforeElement(sf)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 设置用户任务通知
     *
     * @param taskEntity
     */
    public void setUserTaskNotice(TaskEntity taskEntity) {
        String procInstId = taskEntity.getProcessInstanceId();
        String activityId = taskEntity.getTaskDefinitionKey();
        String taskId = taskEntity.getId();
        ProcessInstance processInstance = processInstanceRepository.findById(procInstId);
        FlowElement flowElement = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId()).getMainProcess().getFlowElement(activityId);
        if (flowElement instanceof UserTask) {
            FlowReTimeoutSettingRepository flowReTimeoutSettingRepository = SpringUtils.getBean(FlowReTimeoutSettingRepository.class);
            flowReTimeoutSettingRepository.copyReTimeoutSetting(processInstance.getDeploymentId(), procInstId, activityId, taskId);
            sendTaskHandleNotice(taskEntity);
        }
    }

    /**
     * 触发任务处理通知类型的通知
     *
     * @param taskEntity
     */
    public void sendTaskHandleNotice(TaskEntity taskEntity) {
        FlowProcessInstanceTraceRepository processInstanceTraceRepository = SpringUtils.getBean(FlowProcessInstanceTraceRepository.class);
        FlowProcessInstanceTraceVo pt = processInstanceTraceRepository.getProcessInstanceTraceByProcessInstanceId(taskEntity.getProcessInstanceId());
        if (StringUtils.isNotBlank(taskEntity.getAssignee())) {
            sendTaskStartMessage(pt, taskEntity, taskEntity.getAssignee());
        }
        if (!CollectionUtils.isEmpty(taskEntity.getIdentityLinks())) {
            Set<IdentityLinkEntity> identityLinks = new HashSet<>(taskEntity.getIdentityLinks());
            //实现多人发送
            for (IdentityLinkEntity entity : identityLinks) {
                sendTaskStartMessage(pt, taskEntity, entity.getUserId());
            }
        }
    }


    public void sendTaskStartMessage(FlowProcessInstanceTraceVo pt, TaskEntity taskEntity, String userCode) {
        MessageSenderManager senderManager = SpringUtils.getBean(MessageSenderManager.class);
        Map<String, Object> map = resolveTemplateParams(pt, userCode, taskEntity.getName());
        //获取消息模板
        FlowNoticeTemplateRepository flowNoticeTemplateRepository = SpringUtils.getBean(FlowNoticeTemplateRepository.class);
        List<FlowNoticeTemplateVo> templateListByType = flowNoticeTemplateRepository.getTemplateListByType(MsgTypeEnum.TASK_START_NOTICE.getCode());
        if (!CollectionUtils.isEmpty(templateListByType)) {
            MessageSenderContext build = MessageSenderContext.builder()
                    .processInstanceId(taskEntity.getProcessInstanceId())
                    .title(MessageFillUtils.replaceWithMap(templateListByType.get(0).getTitle(), map))
                    .body(MessageFillUtils.replaceWithMap(templateListByType.get(0).getContent(), map))
                    .processName(pt.getModelName())
                    .senderCode(pt.getStarterId())
                    .senderName(pt.getStarterName())
                    .taskId(taskEntity.getId())
                    .type(MsgTypeEnum.TASK_START_NOTICE.getCode())
                    .receiverCode(userCode)
                    .receiverName(getReceiverName(userCode))
                    .build();
            senderManager.send(build);
        }
    }

    public String getReceiverName(String userCode) {
        if (StringUtils.isBlank(userCode)) {
            return "";
        }
        FlowParticipantRepository participantService = SpringUtils.getBean(FlowParticipantRepository.class);
        FlowParticipantInfoVo participant = participantService.findByParticipantId(userCode);
        if (Objects.isNull(participant)) {
            OrgAccountServiceAdapter orgAccountService = SpringUtils.getBean(OrgAccountServiceAdapter.class);
            ResultResponse<AccountInfo> currentAccountInfo = orgAccountService.getAccountInfoByCode(userCode);
            if (currentAccountInfo.getSuccess()) {
                participant = new FlowParticipantInfoVo();
                participant.setParticipantId(userCode);
                participant.setParticipantType("STA");
                participant.setParticipantName(currentAccountInfo.getData().getUsername());
                participant.setCreateTime(new Date());
                participant.setUpdateTime(new Date());
                FlowParticipantRepository flowParticipantRepository = SpringUtils.getBean(FlowParticipantRepository.class);
                flowParticipantRepository.insertParticipant(participant);
            }
        }
        return Objects.nonNull(participant) ? participant.getParticipantName() : "";
    }


    private Map<String, Object> resolveTemplateParams(FlowProcessInstanceTraceVo pt, String userCode, String activityId) {
        Map<String, Object> result = new HashMap<>(8);
        result.put("taskName", activityId);
        if (Objects.nonNull(pt)) {
            result.put("processName", pt.getModelName());
            result.put("originator", pt.getStarterName());
        }
        result.put("currentHandler", userCode);
        return result;
    }


    public List<UserTask> getFirstTasks(String processDefinationId) {
        FlowGraphTraveller flowGraphTraveller = new FlowGraphTraveller(
                repositoryService.getBpmnModel(processDefinationId).getMainProcess());

        return flowGraphTraveller.findFirstUserTasks();
    }

    public boolean checkCurrentElementIdValid(Process mainProcess, String elementId) {
        FlowElement flowElement = mainProcess.getFlowElement(elementId);
        if (flowElement != null) {
            return true;
        }
        return false;

    }
}
